package com.ceair.store;

import com.ceair.entity.MongoChatMemory;
import com.ceair.mongodb.MongoChatMemoryStoreRepository;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.ChatMessageDeserializer;
import dev.langchain4j.data.message.ChatMessageSerializer;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * @author wangbaohai
 * @ClassName MongoChatMemoryStore
 * @description: 存储会话记忆自定义实现-基于mongodb
 * @date 2025年05月18日
 * @version: 1.0.0
 */
@Component
@RequiredArgsConstructor
public class MongoChatMemoryStore implements ChatMemoryStore {

    private final MongoChatMemoryStoreRepository mongoChatMemoryStoreRepository;

    /**
     * 根据输入的标识符对象获取对应的聊天消息列表。
     *
     * <p>该方法首先尝试将输入对象转换为字符串，并解析为整数类型的 messageId，
     * 然后通过 Spring Data 的 Example 查询机制在 MongoDB 中查找对应的 MongoChatMemory 记录，
     * 最后将其内容反序列化为 ChatMessage 列表返回。</p>
     *
     * <ul>
     *     <li>如果输入为 null 或无法解析为整数，则返回空列表。</li>
     *     <li>若数据库中未找到对应记录，也返回空列表。</li>
     * </ul>
     *
     * @param o 表示消息标识符的对象，通常应为可解析为整数的字符串或数字类型。
     * @return 与指定标识符关联的聊天消息列表，若不存在则返回空列表。
     */
    @Override
    public List<ChatMessage> getMessages(Object o) {
        // 用于存储解析后的消息ID
        int memoryId;

        // 如果输入对象为空，直接返回空列表
        if (o == null) {
            return new LinkedList<>();
        }

        try {
            // 将输入对象转为字符串并尝试解析为整数
            String str = o.toString();
            memoryId = Integer.parseInt(str);
        } catch (NumberFormatException e) {
            // 若字符串无法解析为整数，返回空列表
            return new LinkedList<>();
        }

        // 构建查询条件：根据 memoryId 查询 MongoChatMemory 记录
        MongoChatMemory mongoChatMemoryQuery = new MongoChatMemory();
        mongoChatMemoryQuery.setMemoryId(memoryId);
        Example<MongoChatMemory> example = Example.of(mongoChatMemoryQuery);

        // 执行查询操作，findOne 返回 Optional 对象以避免空指针异常
        MongoChatMemory mongoChatMemory = mongoChatMemoryStoreRepository.findOne(example).orElse(null);

        // 如果查到记录，使用 ChatMessageDeserializer 反序列化 JSON 内容为 ChatMessage 列表
        if (mongoChatMemory != null) {
            return ChatMessageDeserializer.messagesFromJson(mongoChatMemory.getContent());
        } else {
            // 若未查到记录，返回空列表
            return new LinkedList<>();
        }
    }

    /**
     * 更新消息列表
     * 此方法旨在将给定的消息列表更新到数据库中，基于一个标识符来定位消息组
     * 它首先检查提供的对象是否可以转换为整数（消息ID），然后使用该ID更新消息列表
     * 如果提供的对象为空或消息列表为空，此方法将不执行任何操作
     *
     * @param o    一个对象，预期为一个可以转换为整数的字符串，用作消息ID
     * @param list 一个ChatMessage对象列表，包含要更新的消息
     */
    @Override
    public void updateMessages(Object o, List<ChatMessage> list) {
        // 用于存储解析后的消息ID
        int memoryId;

        // 如果输入对象为空，直接返回空列表
        if (o != null && !list.isEmpty()) {
            try {
                // 将输入对象转为字符串并尝试解析为整数
                String str = o.toString();
                memoryId = Integer.parseInt(str);
            } catch (NumberFormatException e) {
                // 若字符串无法解析为整数，不执行更新操作
                return;
            }

            // 构建查询条件：根据 memoryId 查询 MongoChatMemory 记录
            MongoChatMemory mongoChatMemoryQuery = new MongoChatMemory();
            mongoChatMemoryQuery.setMemoryId(memoryId);
            Example<MongoChatMemory> example = Example.of(mongoChatMemoryQuery);

            // 先执行查询操作，findOne 返回 Optional 对象以避免空指针异常
            MongoChatMemory mongoChatMemory = mongoChatMemoryStoreRepository.findOne(example).orElse(null);

            if (!Objects.isNull(mongoChatMemory)) {
                // 如果查到记录，使用 ChatMessageDeserializer 反序列化 JSON 内容为 ChatMessage 列表
                // 调用MongoDB存储库方法，按消息ID更新消息列表
                mongoChatMemoryStoreRepository.updateMessagesByMemoryId(memoryId,
                        ChatMessageSerializer.messagesToJson(list));
            } else {
                // 如果未查到记录，执行新增操作
                MongoChatMemory toAddMongoChatMemory = new MongoChatMemory();
                toAddMongoChatMemory.setMemoryId(memoryId);
                toAddMongoChatMemory.setContent(ChatMessageSerializer.messagesToJson(list));
                mongoChatMemoryStoreRepository.save(toAddMongoChatMemory);
            }
        }
    }

    /**
     * 重写删除消息方法
     * 该方法旨在处理和删除给定的对象所代表的消息
     * 它首先尝试将输入对象解析为消息ID，然后执行删除操作
     *
     * @param o 待删除的消息的标识对象它可以是一个能够被转换为整数字符串的任意对象
     */
    @Override
    public void deleteMessages(Object o) {
        // 用于存储解析后的消息ID
        int memoryId;

        // 如果输入对象为空，直接返回空列表
        if (o != null) {
            try {
                // 将输入对象转为字符串并尝试解析为整数
                String str = o.toString();
                memoryId = Integer.parseInt(str);
            } catch (NumberFormatException e) {
                // 若字符串无法解析为整数，不执行删除操作
                return;
            }

            // 派生查询方式 执行删除操作
            mongoChatMemoryStoreRepository.deleteByMemoryId(memoryId);
        }
    }

}
